<template>
  <div class="p-lyric">
    <div class="p-lyric__voice"></div>
    <base-scroll class="content-wrapper" ref="scroll"
      :options="scrollOptions"
      :data="lyric">
      <div class="p-lyric__content" ref="content"
        :style="{ padding: `${contentPaddingTop} 20px` }">
        <p class="lyric-line"
          :ref="line.time"
          v-for="(line, i) of lyric" :key="i">{{ line.text }}</p>
      </div>
    </base-scroll>
  </div>
</template>

<script>
import { addClass, removeClass } from '@/utils'

export default {
  name: 'player-lyric',
  props: {
    songId: { type: Number, require: true },
    ct: { type: Number, require: true }
  },
  data () {
    return {
      lyric: [],
      contentPaddingTop: 0, // content 上下 padding
      currentLine: null, // 当前播放的行
      scrollImmediate: true, // 是否立即滚动，当 touchmove 滚动歌词时，该值应该为 false
      scrollDelay: 3000, // 滚动的延迟，当不再 touchmove 滚动歌词时，下一次自动滚动的延迟
      scrollTimer: null, // 下一次滚动的 timer
      scrollOptions: {
        scrollX: false,
        scrollY: true,
        click: true
      }
    }
  },
  mounted () {
    this.initData()
    this.$nextTick(_ => {
      this.contentPaddingTop = this.scroll.$el.clientHeight / 2 + 'px'
      // 添加事件，touchmove 滚动歌词后的一段事件内不会自动滚动(不知道为什么 flick 不生效)
      this.scroll.getScroll().on('touchEnd', () => {
        this.timer && clearTimeout(this.timer)
        this.scrollImmediate = false
        this.timer = setTimeout(() => {
          this.scroll.scrollToElement(this.currentLine, 500, true, true)
          this.scrollImmediate = true
        }, this.scrollDelay)
      })
    })
  },
  destroyed () {
    this.scroll.destroy()
  },
  computed: {
    content () {
      return this.$refs.content
    },
    scroll () {
      return this.$refs.scroll
    },
    times () {
      return this.lyric.map(v => v.time)
    }
  },
  methods: {
    initData () {
      this.$api.getLyric(this.songId).then(res => {
        const { data } = res
        if (!data.lrc) {
          this.lyric = [{ time: 0, text: '暂时没有歌词' }]
        } else {
          this.lyric = this.extractLyric(data.lrc.lyric).filter(v => v.text)
        }
        this.scroll.scrollTop()
      })
    },
    /**
     * lyric is a string.
     * return like [{ time: 89122, text: 'some lyric...' }, ...]
     */
    extractLyric (lyric) {
      return lyric.split('\n').map(v => {
        const patch = v.split(']')
        const time = patch[0] && this.decodeLyricTime(patch[0].substr(1))
        const text = patch[1] && patch[1].trim()
        // console.log({ time, text })
        return { time, text }
      })
    },
    decodeLyricTime (time) {
      const times = time.replace('.', ':').split(':').map(Number)
      return (times[0] * 60 * 1000) + (times[1] * 1000) + times[2]
    },
    handleLyricScroll () {
      // 必须引用 this.ct，否则在循环中它的值会变化
      const ct = this.ct
      let index = 0
      // 从 1 开始遍历，未超出 times[i] 时，保留之前的 index
      for (let i = 1, len = this.times.length; i < len; i++) {
        if (ct < this.times[i]) {
          index = i - 1
          break
        }
        // fixed：确保最后一句歌曲会停留到播放完毕
        if (i === len - 1) {
          index = i
        }
      }
      this.currentLine = this.$refs[this.times[index]][0]
      // console.log(this.currentLine)
      // fixed：将滚动操作移至 watch currentLine 中，减少无效的 scroll
    }
  },
  watch: {
    songId (newVal, oldVal) {
      this.initData()
    },
    ct (newVal) {
      // 触发 scroll 滚动
      this.handleLyricScroll()
    },
    currentLine (newEl, oldEl) {
      // 动态修改类名
      oldEl && removeClass(oldEl, 'is-current')
      addClass(newEl, 'is-current')
      if (this.scrollImmediate) {
        this.$refs.scroll.scrollToElement(newEl, 500, true, true)
      }
    }
  }
}
</script>

<style lang="scss" scoped>
.p-lyric {
  display: flex;
  flex-direction: column;
  height: 0;
  /* background-color: rgba(0, 0, 0, .4); */
  &__voice {
    height: .4rem;
  }
  .content-wrapper {
    flex: 1;
    box-sizing: border-box;
    overflow: hidden;
    height: 0;
  }
  &__content {
    // Todo: 使用 gradient 制作上下模糊渐变
    .lyric-line {
      padding: .1rem 0;
      line-height: .2rem;
      white-space: wrap;
      text-align: center;
      font-size: .14rem;
      color: #9d9d9d;
      transition: all .3s;
      &.is-current {
        color: #fff;
        font-size: .16rem;
      }
    }
  }
}
</style>
